/**
 *******************************************************************************
 * @FileName  : tlsr825x_gpio.c
 * @Author    : GaoQiu ---- gq_ttxshang@163.com
 * @CreateDate: 2020-09-10
 * @Copyright : Copyright(C) GaoQiu
 *              All Rights Reserved.
 *
 *******************************************************************************
 *
 * The information contained herein is confidential and proprietary property of
 * GaoQiu and is available under the terms of Commercial License Agreement
 * between GaoQiu and the licensee in separate contract or the terms described
 * here-in.
 *
 * This heading MUST NOT be removed from this file.
 *
 * Licensees are granted free, non-transferable use of the information in this
 * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
 *
 *******************************************************************************
 */
#include "tlsr825x.h"
#include "tlsr825x_gpio.h"

#include "utils/assert.h"
#include "utils/track.h"

#define GPIO_GRP_NUM   4  /*!< Define supported the number of GPIO groups. */
#define GPIO_PIN_NUM   8  /*!< Define the number of pins per GPIO group.   */
#define GPIO_AF_NUM    3  /*!< Define the number of AF per Pin.            */

#define GPIOB_IE_ANA_REG   0xbd /*!< GPIO B input enable(IE) analog register address. */
#define GPIOB_DS_ANA_REG   0xbf /*!< GPIO B data strength(DS) analog register address.*/

#define GPIOC_IE_ANA_REG   0xc0 /*!< GPIO C input enable(IE) analog register address. */
#define GPIOC_DS_ANA_REG   0xc2 /*!< GPIO C input enable(IE) analog register address. */

#define GPIO_PULL_ANA_BASE 0x0e /*!< GPIO pull up/down analog register base address.  */

/*!   GPIO AF map table declaration. */
static const uint8_t gpioAFTbl[GPIO_GRP_NUM][GPIO_PIN_NUM][GPIO_AF_NUM];

/**
 * @brief  : GPIO default initialization.
 * @param  : None.
 * @return : None.
 */
void GPIO_DefInit(void)
{
	/**
	 * Define GPIO configuration:
	 * 1. Input disable.
	 * 2. Output disable.
	 * 3. GPIO Function.
	 * 4. Strength data.
	 * 5. data output/input = 0.
	 * 6. Pull down.
	 */

	/* GPIOA */
	GPIOA->DI = 0x80;//input 0        PA[7]->SWS
	GPIOA->DO = 0x00;//output 0
	GPIOA->IE = 0x80;//input disable; PA[7]->SWS
	GPIOA->OEN =0xFF;//output disable;
	GPIOA->DS = 0xFF;//strong data
	GPIOA->FN = 0x7F;//AS_GPIO        PA[7]->SWS

	/* GPIOB */
	GPIOB->DI = 0x00;//input 0
	GPIOB->DO = 0x00;//output 0
	analog_write(GPIOB_IE_ANA_REG, 0x00);//input disable;
	GPIOB->OEN =0xFF;//output disable;
	analog_write(GPIOB_DS_ANA_REG, 0xff);//strong data
	GPIOB->FN = 0xFF;//AS_GPIO

	/* GPIOC */
	GPIOC->DI = 0x00;//input 0
	GPIOC->DO = 0x00;//output 0
	analog_write(GPIOC_IE_ANA_REG, 0x00);//input disable;
	GPIOC->OEN =0xFF;//output disable;
	analog_write(GPIOC_DS_ANA_REG, 0xff);//strong data
	GPIOC->FN = 0xFF;//AS_GPIO

	/* GPIOD */
	GPIOD->DI = 0x00;//input 0
	GPIOD->DO = 0x00;//output 0
	GPIOD->IE = 0x00;//input disable;
	GPIOD->OEN =0xFF;//output disable;
	GPIOD->DS = 0xFF;//strong data
	GPIOD->FN = 0xFF;//AS_GPIO

	/* GPIO Pull floating */
	for(int i=0; i<GPIO_GRP_NUM; i++)
	{
		analog_write(GPIO_PULL_ANA_BASE + i*2,     0x00);
		analog_write(GPIO_PULL_ANA_BASE + i*2 + 1, 0x00);
	}
}

/**
 * @brief  : GPIO initialization.
 * @param  : GPIOx               can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_InitStruct     Pointer point to GPIO initialization struct.
 * @return : None.
 */
void GPIO_Init(GPIO_Type_t *GPIOx, GPIO_InitType_t *GPIO_InitStruct)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);
    ASSERT(IS_GPIO_MODE_VALID(GPIO_InitStruct->GPIO_Mode), DRIV_ERR_INVALID_PARAM);
    ASSERT(IS_GPIO_PULL_VALID(GPIO_InitStruct->GPIO_Pull), DRIV_ERR_INVALID_PARAM);

	uint8_t pinMask = (uint8_t)GPIO_InitStruct->GPIO_Pin;

	/* GPIO Alternative Function setting */
	if(GPIO_InitStruct->GPIO_Mode & GPIO_MODE_AF_MASK){
		GPIOx->FN &= ~pinMask; //Set Alternative Function.
	}else{
		GPIOx->FN |= pinMask;  //Set GPIO Function.
	}

	/* GPIO Pull setting */
	uint8_t gpioGrpId = (uint8_t)(((uint32_t)GPIOx - (uint32_t)GPIOA)>>3);
	uint8_t pullAddr  = GPIO_PULL_ANA_BASE + (gpioGrpId << 1);

	for(int i=0; i<GPIO_PIN_NUM; i++)
	{
		if(pinMask & (1<<i)){
			uint8_t tmpAddr = pullAddr + (i>>2); // i*2/8
			uint8_t val = analog_read(tmpAddr);
			val &= ~(0x03<<((i%4)<<1));
			val |= ((uint8_t)GPIO_InitStruct->GPIO_Pull<<((i%4)<<1));
			analog_write( tmpAddr, val);
		}
	}

	if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_In_Out){
		GPIOx->OEN &= ~pinMask;
	}

	if(GPIOx == GPIOA || GPIOx == GPIOD)
	{
		if(GPIO_InitStruct->GPIO_Mode & GPIO_MODE_OUT_MASK)
		{
			GPIOx->OEN &= ~pinMask;
			GPIOx->IE  &= ~pinMask;
		}
		else
		{
			GPIOx->IE  |= pinMask;
			GPIOx->OEN |= pinMask;
		}
	}
	else if(GPIOx == GPIOB)
	{
		if(GPIO_InitStruct->GPIO_Mode & GPIO_MODE_OUT_MASK)
		{
			GPIOx->OEN &= ~pinMask; //Enable Output.
			analog_write(GPIOB_IE_ANA_REG, analog_read(GPIOB_IE_ANA_REG) & ~pinMask);
		}
		else
		{
			analog_write(GPIOB_IE_ANA_REG, analog_read(GPIOB_IE_ANA_REG) | pinMask);
			GPIOx->OEN |= pinMask;
		}
	}
	else if(GPIOx == GPIOC)
	{
		if(GPIO_InitStruct->GPIO_Mode & GPIO_MODE_OUT_MASK)
		{
			GPIOx->OEN &= ~pinMask; //Enable Output.
			analog_write(GPIOC_IE_ANA_REG, analog_read(GPIOC_IE_ANA_REG) & ~pinMask);
		}
		else
		{
			analog_write(GPIOC_IE_ANA_REG, analog_read(GPIOC_IE_ANA_REG) | pinMask);
			GPIOx->OEN |= pinMask;
		}
	}
}

/**
 * @brief  : Set GPIO altern function.
 * @param  : GPIOx               can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin            can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @param  : GPIO_AFunc          can be GPIO_AF_UART/GPIO_AF_SPI/GPIO_AF_IIC...
 * @return : None.
 */
void GPIO_SetAlternFunc(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin, uint16_t GPIO_AFunc)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	if(GPIO_AFunc == GPIO_AF_NONE){
		return;
	}

	uint8_t  gpioGrpId = (uint8_t)(((uint32_t)GPIOx - (uint32_t)GPIOA)>>3);
	uint16_t *GPIOx_AF = (uint16_t *)&GPIO_AF->PA_AF + gpioGrpId;
	uint8_t  pinMask = (uint8_t)GPIO_Pin;
	uint8_t  pin = 0;
	uint16_t tmp = 0;

	for(pin=0; pin<GPIO_PIN_NUM; pin++)
	{
		if(!(pinMask & (1<<pin))){
			continue;
		}

		for(int i=0; i<GPIO_AF_NUM; i++)
		{
			if(gpioAFTbl[gpioGrpId][pin][i] == GPIO_AFunc){
				tmp = *GPIOx_AF;
				tmp &= ~GPIO_PIN_X_AF(pin);
				tmp |= (uint16_t)(i << (pin<<1));
				*GPIOx_AF = tmp;
			}
		}
	}
}

/**
 * @brief  : Remap GPIO Alternative function.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @param  : GPIO_AF_Remap   can be GPIOA3_AF_Remap_SPI_IN/GPIOA3_AF_Remap_SPI_OUT...
 * @return : None.
 */
void GPIO_RemapAlternFunc(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin, uint16_t GPIO_AF_Remap)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	uint16_t *GPIO_AF_Mux = (uint16_t *)GPIO_AF_MUX;
    bool_t valid = false;

	if(GPIOx == GPIOA && (GPIO_Pin & (GPIO_Pin_3|GPIO_Pin_4)))
	{
		if(GPIO_Pin & GPIO_Pin_3){
			*GPIO_AF_Mux &= ~(GPIOA3_AF_SPI_IN | GPIOA3_AF_IIC_IN | GPIOA3_AF_SPI_IIC_OUT);
			valid = true;
		}
		else if(GPIO_Pin & GPIO_Pin_4){
			*GPIO_AF_Mux &= ~(GPIOA4_AF_SPI_IN | GPIOA4_AF_IIC_IN | GPIOA4_AF_SPI_IIC_OUT);
			valid = true;
		}
	}
	else if(GPIOx == GPIOB && (GPIO_Pin & GPIO_Pin_6))
	{
		*GPIO_AF_Mux &= ~(GPIOB6_AF_SPI_IN | GPIOB6_AF_IIC_IN | GPIOB6_AF_SPI_IIC_OUT);
		valid = true;
	}
	else if(GPIOx == GPIOD && (GPIO_Pin & GPIO_Pin_7))
	{
		*GPIO_AF_Mux &= ~(GPIOD7_AF_SPI_IN | GPIOD7_AF_IIC_IN | GPIOD7_AF_SPI_IIC_OUT);
		valid = true;
	}
	else{
		return;
	}

	/* GPIO AF Remap */
	if(valid){
		*GPIO_AF_Mux |= GPIO_AF_Remap;
	}
}

/**
 * @brief  : Set GPIO pull mode.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @param  : GPIO_Pull       can be GPIO_Pull_Floating/GPIO_PullDown/GPIO_PullUp_Strong...
 * @return : None.
 */
void GPIO_SetPullMode(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin, GPIOPull_Type_t GPIO_Pull)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	uint8_t gpioGrpId = (uint8_t)(((uint32_t)GPIOx - (uint32_t)GPIOA)>>3);
	uint8_t pinMask   = (uint8_t)GPIO_Pin;
	uint8_t pullAddr  = GPIO_PULL_ANA_BASE + (gpioGrpId << 1);

	for(int i=0; i<GPIO_PIN_NUM; i++)
	{
		if(pinMask & (1<<i)){
			uint8_t tmpAddr = pullAddr + (i>>2); // i*2/8
			uint8_t val = analog_read(tmpAddr);
			val &= ~(0x03<<((i%4)<<1));
			val |= ((uint8_t)GPIO_Pull<<((i%4)<<1));
			analog_write(tmpAddr, val);
		}
	}
}

/**
 * @brief  : Read GPIO input bit value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @return : return GPIO bit value.
 */
uint8_t GPIO_ReadInputBit(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	return (GPIOx->DI & GPIO_Pin) ? 1:0;
}

/**
 * @brief  : Read GPIO output bit value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @return : return GPIO bit value.
 */
uint8_t GPIO_ReadOutputBit(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	return (GPIOx->DO & GPIO_Pin) ? 1 : 0;
}

/**
 * @brief  : Write GPIO bits value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @return : None.
 */
void GPIO_WriteBits(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin, bool_t bitValue)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	if(bitValue){
		GPIOx->DO |= (uint8_t)GPIO_Pin;
	}
	else{
		GPIOx->DO &= ~(uint8_t)GPIO_Pin;
	}
}

/**
 * @brief  : Toggle GPIO bit value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @return : None.
 */
void GPIO_ToggleBits(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	GPIOx->DO ^= (uint8_t)GPIO_Pin;
}

/**
 * @brief  : Read GPIO output value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @return : return GPIO value.
 */
uint8_t GPIO_ReadOutputData(GPIO_Type_t *GPIOx)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	return GPIOx->DO;
}

/**
 * @brief  : Read GPIO input value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @return : return GPIO value.
 */
uint8_t GPIO_ReadInputData(GPIO_Type_t *GPIOx)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	return GPIOx->DI;
}

/**
 * @brief  : Write GPIO input value.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : value           value to be wrote.
 * @return : None.
 */
void GPIO_Write(GPIO_Type_t *GPIOx, uint8_t value)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	GPIOx->DO = value;
}

/**
 * @brief  : Set GPIO Interrupt.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @param  : GPIO_Trigger    can be GPIO_Trigger_Rising/GPIO_Trigger_Falling.
 * @param  : enable          enable / diable interrupt.
 * @return : None.
 */
void GPIO_ITConfig(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin, GPIOTrigger_Type_t GPIO_Trigger, bool_t enable)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	if(enable){
		GPIOx->IRQ_MASK |= (uint8_t)GPIO_Pin;
	}
	else{
		GPIOx->IRQ_MASK &= ~(uint8_t)GPIO_Pin;
		return;
	}

	if(GPIO_Trigger == GPIO_Trigger_Falling)
	{
		GPIOx->POL |= (uint8_t)GPIO_Pin;
	}
	else{
		GPIOx->POL &= ~(uint8_t)GPIO_Pin;
	}

	REG_8(0x5b5) |= 0x08;//bit3: Enable GPIO interrupt.
}

void GPIO_IT_Enable(void)
{
	REG_8(0x5b5) |= 0x08;//bit3: Enable GPIO interrupt.
}

void GPIO_IT_Disable(void)
{
	REG_8(0x5b5) &= ~0x08;//bit3: Disable GPIO interrupt.
}

/**
 * @brief  : Get GPIO Interrupt state.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @return : 1 if interrupt is valid or 0.
 */
uint8_t GPIO_GetState(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	uint8_t gpioGrpId = (uint8_t)(((uint32_t)GPIOx - (uint32_t)GPIOA)>>3);
	uint8_t *pGPIO_IRQ_State = (uint8_t *)&GPIO_IRQ_STATE->PA_IRQ_STATE + gpioGrpId;

	return (*pGPIO_IRQ_State & GPIO_Pin) ? 1:0;
}

/**
 * @brief  : Get GPIO Interrupt state.
 * @param  : GPIOx           can be GPIOA/GPIOB/GPIOC/GPIOD....
 * @param  : GPIO_Pin        can be GPIO_Pin_0/GPIO_Pin_1/GPIO_Pin_2/GPIO_Pin_3...
 * @param  : wakePol         wake level.
 * @param  : enable          enable / disable wake up.
 * @return : None.
 */
void GPIO_SetWakeup(GPIO_Type_t *GPIOx, uint16_t GPIO_Pin, GPIOWakePol_Type_t wakePol, bool_t enable)
{
	ASSERT(IS_GPIO_GRP(GPIOx), DRIV_ERR_INVALID_PARAM);

	uint8_t gpioGrpId = (uint8_t)(((uint32_t)GPIOx - (uint32_t)GPIOA)>>3);
	uint8_t polAddr = 0x21 + gpioGrpId;
	uint8_t enAddr  = 0x27 + gpioGrpId;

	if(enable){
		analog_write(enAddr, analog_read(enAddr)|GPIO_Pin);
	}
	else{
		analog_write(enAddr, analog_read(enAddr) & ~GPIO_Pin);
		return;
	}

	if(!wakePol){
		analog_write(polAddr, analog_read(polAddr)|GPIO_Pin);
	}
	else{
		analog_write(polAddr, analog_read(polAddr) & ~GPIO_Pin);
	}
}


/*******************************************************************************
 *
 *  This set of APIs can also be used. It is designed for use in special situations.
 *
 ******************************************************************************/
void GPIO_InitEx(uint16_t GPIO_Pn, GPIOMode_Type_t GPIO_Mode)
{
	uint8_t gpioGrpId  = GPIO_GRP_ID(GPIO_Pn);
	uint8_t pinMask    = GPIO_PIN_MASK(GPIO_Pn);
	GPIO_Type_t *GPIOx = GPIOA + gpioGrpId;//[!important]

	if(gpioGrpId >= GPIO_GRP_NUM){
		return; // not support GPIO Group.
	}

	/* GPIO Alternative Function setting */
	if(GPIO_Mode & GPIO_MODE_AF_MASK){
		GPIOx->FN &= ~pinMask; //Set Alternative Function.
	}else{
		GPIOx->FN |= pinMask;  //Set GPIO Function.
	}

	switch(GPIO_Mode)
	{
	case GPIO_Mode_In:
	case GPIO_Mode_AF_In:
		/* Disable Output */
		GPIOx->OEN |= pinMask;

		/* Enable Input */
		if(gpioGrpId == GPIO_GRP_ID(GPIOA_GRP) || gpioGrpId == GPIO_GRP_ID(GPIOD_GRP))//GPIOA/GPIOD
		{
			GPIOx->IE  |= pinMask;
		}
		else if(gpioGrpId == GPIO_GRP_ID(GPIOB_GRP))//GPIOB
		{
			analog_write(GPIOB_IE_ANA_REG, analog_read(GPIOB_IE_ANA_REG)|pinMask);
		}
		else if(gpioGrpId == GPIO_GRP_ID(GPIOC_GRP))//GPIOC
		{
			analog_write(GPIOC_IE_ANA_REG, analog_read(GPIOC_IE_ANA_REG)|pinMask);
		}
		break;

	case GPIO_Mode_In_Out:
		/* Enable Output */
		GPIOx->OEN &= ~pinMask;

		/* Enable Input */
		if(gpioGrpId == GPIO_GRP_ID(GPIOA_GRP) || gpioGrpId == GPIO_GRP_ID(GPIOD_GRP))//GPIOA/GPIOD
		{
			GPIOx->IE  |= pinMask;
		}
		else if(gpioGrpId == GPIO_GRP_ID(GPIOB_GRP))//GPIOB
		{
			analog_write(GPIOB_IE_ANA_REG, analog_read(GPIOB_IE_ANA_REG)|pinMask);
		}
		else if(gpioGrpId == GPIO_GRP_ID(GPIOC_GRP))//GPIOC
		{
			analog_write(GPIOC_IE_ANA_REG, analog_read(GPIOC_IE_ANA_REG)|pinMask);
		}
		break;

	case GPIO_Mode_Out:
	case GPIO_Mode_AF_Out:
		/* Enable Output */
		GPIOx->OEN &= ~pinMask;

		/* Dsiable Input */
		if(gpioGrpId == GPIO_GRP_ID(GPIOA_GRP) || gpioGrpId == GPIO_GRP_ID(GPIOD_GRP))//GPIOA/GPIOD
		{
			GPIOx->IE  &= ~pinMask;
		}
		else if(gpioGrpId == GPIO_GRP_ID(GPIOB_GRP))//GPIOB
		{
			analog_write(GPIOB_IE_ANA_REG, analog_read(GPIOB_IE_ANA_REG) & ~pinMask);
		}
		else if(gpioGrpId == GPIO_GRP_ID(GPIOC_GRP))//GPIOC
		{
			analog_write(GPIOC_IE_ANA_REG, analog_read(GPIOC_IE_ANA_REG) & ~pinMask);
		}
		break;
	default:
		break;
	}
}

void GPIO_SetAlternFuncEx(uint16_t GPIO_Pn, uint16_t GPIO_AFunc)
{
	uint8_t  gpioGrpId = GPIO_GRP_ID(GPIO_Pn);
	uint8_t  pinMask   = GPIO_PIN_MASK(GPIO_Pn);
	uint16_t *GPIOx_AF = (uint16_t *)((uint16_t *)&GPIO_AF->PA_AF + gpioGrpId);
	uint16_t tmp = 0;
	uint8_t  pin = 0;

	if(gpioGrpId >= GPIO_GRP_NUM || GPIO_AFunc == GPIO_AF_NONE){
		return; // Not support GPIO Group or Alternative Function.
	}

	for(pin=0; pin<GPIO_PIN_NUM; pin++)
	{
		if(!(pinMask & (1<<pin))){
			continue;
		}

		for(int i=0; i<GPIO_AF_NUM; i++)
		{
			if(gpioAFTbl[gpioGrpId][pin][i] == GPIO_AFunc){
				tmp = *GPIOx_AF;
				tmp &= ~GPIO_PIN_X_AF(pin);
				tmp |= (uint16_t)(i << (pin<<1));
				*GPIOx_AF = tmp;
			}
		}
	}
}

void GPIO_RemapAlternFuncEx(uint16_t GPIO_Pn, uint16_t GPIO_AF_Remap)
{
	uint8_t  pinMask = GPIO_PIN_MASK(GPIO_Pn);
	uint16_t *GPIO_AF_Mux = (uint16_t *)GPIO_AF_MUX;
	bool_t   valid = false;
	uint16_t value = *GPIO_AF_Mux;

	switch(GPIO_Pn & GPIO_GRP_MASK)
	{
	case GPIOA_GRP:
		if(pinMask & GPIO_Pin_3 ){
			value &= ~(GPIOA3_AF_SPI_IN | GPIOA3_AF_IIC_IN | GPIOA3_AF_SPI_IIC_OUT);
			valid = true;
		}
		else if(pinMask & GPIO_Pin_4){
			value &= ~(GPIOA4_AF_SPI_IN | GPIOA4_AF_IIC_IN | GPIOA4_AF_SPI_IIC_OUT);
			valid = true;
		}
		break;
	case GPIOB_GRP:
		if((pinMask & GPIO_Pin_6)){
			value &= ~(GPIOB6_AF_SPI_IN | GPIOB6_AF_IIC_IN | GPIOB6_AF_SPI_IIC_OUT);
			valid = true;
		}
		break;
	case GPIOD_GRP:
		if((pinMask & GPIO_Pin_7)){
			value &= ~(GPIOD7_AF_SPI_IN | GPIOD7_AF_IIC_IN | GPIOD7_AF_SPI_IIC_OUT);
		}
		break;
	default:
		return;
	}

	if(valid){
		*GPIO_AF_Mux = (value | GPIO_AF_Remap);
	}
}

void GPIO_SetPullModeEx(uint16_t GPIO_Pn, GPIOPull_Type_t GPIO_Pull)
{
	uint8_t gpioGrpId  = GPIO_GRP_ID(GPIO_Pn);
	uint8_t pinMask    = GPIO_PIN_MASK(GPIO_Pn);
	uint8_t pullAddr   = GPIO_PULL_ANA_BASE + (gpioGrpId << 1);

	for(int i=0; i<GPIO_PIN_NUM; i++)
	{
		if(pinMask & (1<<i)){
			uint8_t tmpAddr = pullAddr + (i>>2); // i*2/8
			uint8_t val = analog_read(tmpAddr);
			val &= ~(0x03<<((i%4)<<1));
			val |= ((uint8_t)GPIO_Pull<<((i%4)<<1));
			analog_write( tmpAddr, val);
		}
	}
}

uint8_t GPIO_ReadInputBitEx(uint16_t GPIO_Pn)
{
	uint8_t     pinMask = GPIO_PIN_MASK(GPIO_Pn);
	GPIO_Type_t *GPIOx  = GPIOA + GPIO_GRP_ID(GPIO_Pn);//[!important]

	//TRACK("driver -- pinMask:0x%02X, GPIO_GRP:0x%02X\n",pinMask, GPIO_GRP_ID(GPIO_Pn));

	return (GPIOx->DI & pinMask) ? 1:0;
}

uint8_t GPIO_ReadOutputBitEx(uint16_t GPIO_Pn)
{
	uint8_t     pinMask = GPIO_PIN_MASK(GPIO_Pn);
	GPIO_Type_t *GPIOx  = GPIOA + GPIO_GRP_ID(GPIO_Pn);//[!important]

	return (GPIOx->DO & pinMask) ? 1:0;
}

void GPIO_WriteBitsEx(uint16_t GPIO_Pn, bool_t bitValue)
{
	uint8_t     pinMask = GPIO_PIN_MASK(GPIO_Pn);
	GPIO_Type_t *GPIOx  = GPIOA + GPIO_GRP_ID(GPIO_Pn);//[!important]

	if(bitValue){
		GPIOx->DO |= pinMask;
	}
	else{
		GPIOx->DO &= ~pinMask;
	}
}

void GPIO_ToggleBitsEx(uint16_t GPIO_Pn)
{
	uint8_t     gpioGrpId  = GPIO_GRP_ID(GPIO_Pn);
	uint8_t     pinMask    = GPIO_PIN_MASK(GPIO_Pn);
	GPIO_Type_t *GPIOx = GPIOA + gpioGrpId;//[!important]

	GPIOx->DO ^= pinMask;
}

void GPIO_ITConfigEx(uint16_t GPIO_Pn, GPIOTrigger_Type_t GPIO_Trigger, bool_t enable)
{
	uint8_t     pinMask= GPIO_PIN_MASK(GPIO_Pn);
	GPIO_Type_t *GPIOx = GPIOA + GPIO_GRP_ID(GPIO_Pn);//[!important]

	if(enable){
		GPIOx->IRQ_MASK |= pinMask;
	}
	else{
		GPIOx->IRQ_MASK &= ~pinMask;
		return;
	}

	if(GPIO_Trigger == GPIO_Trigger_Falling)
	{
		GPIOx->POL |= pinMask;
	}
	else{
		GPIOx->POL &= ~pinMask;
	}

	REG_8(0x5b5) |= 0x08;//bit3: Enable GPIO interrupt.
}

uint8_t GPIO_GetStateEx(uint16_t GPIO_Pn)
{
	uint8_t *pGPIO_IRQ_State = (uint8_t *)&GPIO_IRQ_STATE->PA_IRQ_STATE + GPIO_GRP_ID(GPIO_Pn);

	return (*pGPIO_IRQ_State & GPIO_PIN_MASK(GPIO_Pn)) ? 1:0;
}

void GPIO_SetWakeupEx(uint16_t GPIO_Pn, GPIOWakePol_Type_t wakePol, bool_t enable)
{
	uint8_t gpioGrpId = GPIO_GRP_ID(GPIO_Pn);
	uint8_t pinMask = GPIO_PIN_MASK(GPIO_Pn);
	uint8_t polAddr = 0x21 + gpioGrpId;
	uint8_t enAddr  = 0x27 + gpioGrpId;

	if(enable){
		analog_write(enAddr, analog_read(enAddr)|pinMask);
	}
	else{
		analog_write(enAddr, analog_read(enAddr) & ~pinMask);
		return;
	}

	if(!wakePol){
		analog_write(polAddr, analog_read(polAddr)|pinMask);
	}
	else{
		analog_write(polAddr, analog_read(polAddr) & ~pinMask);
	}
}





/*!  GPIO AF map table. */
static const uint8_t gpioAFTbl[GPIO_GRP_NUM][GPIO_PIN_NUM][GPIO_AF_NUM] =
{
	/* GPIOA AF Table */
	{
		/* 0                1                  2                   */
		{GPIO_AF_DMIC, GPIO_AF_PWM0_N, GPIO_AF_UART},/*!< GPIO_Pin_0 */
		{GPIO_AF_DMIC, GPIO_AF_NONE,   GPIO_AF_IIS },/*!< GPIO_Pin_1 */
		{GPIO_AF_SPI,  GPIO_AF_UART,   GPIO_AF_PWM0},/*!< GPIO_Pin_2 */
		{GPIO_AF_SPI,  GPIO_AF_UART,   GPIO_AF_PWM1},/*!< GPIO_Pin_3 */
		{GPIO_AF_SPI,  GPIO_AF_UART,   GPIO_AF_PWM2},/*!< GPIO_Pin_4 */
		{GPIO_AF_USB,  GPIO_AF_NONE,   GPIO_AF_NONE},/*!< GPIO_Pin_5 */
		{GPIO_AF_USB,  GPIO_AF_NONE,   GPIO_AF_NONE},/*!< GPIO_Pin_6 */
		{GPIO_AF_SWS,  GPIO_AF_UART,   GPIO_AF_NONE},/*!< GPIO_Pin_7 */
	},

	/* GPIOB AF Table */
	{
		/* 0                1                  2                   */
		{GPIO_AF_PWM3,   GPIO_AF_UART, GPIO_AF_NONE},/*!< GPIO_Pin_0 */
		{GPIO_AF_PWM4,   GPIO_AF_UART, GPIO_AF_NONE},/*!< GPIO_Pin_1 */
		{GPIO_AF_PWM5,   GPIO_AF_UART, GPIO_AF_NONE},/*!< GPIO_Pin_2 */
		{GPIO_AF_PWM0_N, GPIO_AF_UART, GPIO_AF_NONE},/*!< GPIO_Pin_3 */
		{GPIO_AF_SDM,    GPIO_AF_PWM4, GPIO_AF_NONE},/*!< GPIO_Pin_4 */
		{GPIO_AF_SDM,    GPIO_AF_PWM5, GPIO_AF_NONE},/*!< GPIO_Pin_5 */
		{GPIO_AF_SDM,    GPIO_AF_SPI,  GPIO_AF_UART},/*!< GPIO_Pin_6 */
		{GPIO_AF_SDM,    GPIO_AF_SPI,  GPIO_AF_UART},/*!< GPIO_Pin_7 */
	},

	/* GPIOC AF Table */
	{
		/* 0                1                  2                   */
		{GPIO_AF_IIC,    GPIO_AF_PWM4_N, GPIO_AF_UART  },/*!< GPIO_Pin_0 */
		{GPIO_AF_IIC,    GPIO_AF_PWM1_N, GPIO_AF_PWM0  },/*!< GPIO_Pin_1 */
		{GPIO_AF_PWM0,   GPIO_AF_UART,   GPIO_AF_IIC   },/*!< GPIO_Pin_2 */
		{GPIO_AF_PWM3,   GPIO_AF_UART,   GPIO_AF_IIC   },/*!< GPIO_Pin_3 */
		{GPIO_AF_PWM2,   GPIO_AF_UART,   GPIO_AF_PWM0_N},/*!< GPIO_Pin_4 */
		{GPIO_AF_PWM3_N, GPIO_AF_UART,   GPIO_AF_NONE  },/*!< GPIO_Pin_5 */
		{GPIO_AF_NONE,   GPIO_AF_NONE,   GPIO_AF_PWM4_N},/*!< GPIO_Pin_6 */
		{GPIO_AF_NONE,   GPIO_AF_NONE,   GPIO_AF_PWM5_N},/*!< GPIO_Pin_7 */
	},

	/* GPIOD AF Table */
	{
		/* 0                1                  2                   */
		{GPIO_AF_NONE,   GPIO_AF_NONE, GPIO_AF_UART  },/*!< GPIO_Pin_0 */
		{GPIO_AF_NONE,   GPIO_AF_NONE, GPIO_AF_UART  },/*!< GPIO_Pin_1 */
		{GPIO_AF_SPI,    GPIO_AF_IIS,  GPIO_AF_PWM3  },/*!< GPIO_Pin_2 */
		{GPIO_AF_PWM1_N, GPIO_AF_IIS,  GPIO_AF_UART  },/*!< GPIO_Pin_3 */
		{GPIO_AF_SWM,    GPIO_AF_IIS,  GPIO_AF_PWM2_N},/*!< GPIO_Pin_4 */
		{GPIO_AF_PWM0,   GPIO_AF_NONE, GPIO_AF_PWM0_N},/*!< GPIO_Pin_5 */
		{GPIO_AF_SPI,    GPIO_AF_UART, GPIO_AF_NONE  },/*!< GPIO_Pin_6 */
		{GPIO_AF_SPI,    GPIO_AF_IIS,  GPIO_AF_UART  },/*!< GPIO_Pin_7 */
	},
};


